/*
 * ******************************************************************************
 * Class: ServiceNode	
 * 
 * @author: Teresa Mafalda dos Reis Frazao
 * @version:April 10, 2014 
 * 
 * This thread class is the service itself. So it implements ServiceInterface 
 * interface.
 * This class also includes service modifiers and reads. Thus, gets and sets for 
 * variables or for updating LinkedList data structures.    
 * ******************************************************************************
 */
package com.feedzai.service.data;

import java.util.LinkedList;

import com.feedzai.service.ServiceInterface;


/**
 * The Class ServiceNode.
 */
public class ServiceNode implements Runnable, ServiceInterface{

	
	/** The Constant ZERO. */
	private static final int ZERO = 0;

	/** The service id. */
	private Long id;
	
	/** The newthread. */
	private Thread newthread;
	
	/** The service running status. */
	private Boolean runningStatus;
	
	/** The visited. */
	private Boolean visited;
	
	/** The is child from list. 
	 * This list allows BFS algorithm to stop all services.
	 * */
	private LinkedList<Long> isChildFromLinkedList;
	 
	
	/** Is parent from list. 
	 * This list allows BFS algorithm to start all services, 
	 * and perform topological sort.
	 * */
	private LinkedList<Long> isParentFromLinkedList;
	
	
	
	/**
	 * Instantiates a new service node.
	 *
	 * @param id the id
	 */
	public ServiceNode(Long id) 
	{
		this.id = id;
		this.runningStatus = false;
		this.visited = false;
		isChildFromLinkedList = new LinkedList<Long>();
		isParentFromLinkedList = new LinkedList<Long>();
	}
	
	
	/*
	 * ---------------------------------------------------------------------------
	 * 							Public Interface 
	 * ---------------------------------------------------------------------------
	 */
	
	
	/**
	 * Gets the id.
	 *
	 * @return the id
	 */
	public Long getId() 
	{
		return id;
	}
	
	
	/**
	 * Gets the runnig status.
	 *
	 * @return the runnig status
	 */
	private Boolean getrunningStatus() {
		return runningStatus;
	}
	
	/**
	 * Sets the runnig status.
	 *
	 * @param runningStatus the new runnig status
	 */
	private void setRunningStatus(Boolean runningStatus) {
		this.runningStatus = runningStatus;
	}
	
	
	/**
	 * Checks if is visited.
	 *
	 * @return the boolean
	 */
	public Boolean isVisited() {
		return visited;
	}
	
	
	/**
	 * Sets the visited.
	 *
	 * @param visited the new visited
	 */
	public synchronized void setVisited(Boolean visited) {
		this.visited = visited;
	}
	
	
	/**
	 * Checks if service is running.
	 *
	 * @return the boolean
	 */
	@Override
	public boolean isRunning() {
		return getrunningStatus();
	}
	
	
	/**
	 * Starts the service so its status is updated.
	 */
	@Override
	public void start() {
		setRunningStatus(true);
		
		newthread = new Thread (this, id.toString());
		newthread.start ();
		
		System.out.println("I started service: " + this.getId());
	}
	
	
	/**
	 * Stops the service so its status is updated.
	 */
	@Override
	public synchronized void stop() {
		setRunningStatus(false);
		System.out.println("I stoped service: " + this.getId());
	}
	

	/**
	 * Runs the service thread.
	 */
	@Override
	public void run() {
		
		while(runningStatus) {
			// Loop and perform some work
		}
	}
	

	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#addDependency(com.feedzai.service.data.ServiceNode)
	 */
	@Override
	public boolean addIsChildFromDependency(ServiceNode serviceNode) {

		// The ID has to be a natural number and node cannot be null
		if(serviceNode == null || serviceNode.getId() == null || serviceNode.getId().longValue() < ZERO)
		{
			throw new IllegalArgumentException("The node is null or de ID is not valid");
		}
		else
		{
			//
			// We should not consider dependencies which have the same ID as the current service
			// Or dependencies that are already created. Thus, avoid duplicates
			//
			if(serviceNode.getId().equals(this.getId()) || isChildFromLinkedList.contains(serviceNode.getId()))
				return false;
			
			// We include a new dependency with no problems
			isChildFromLinkedList.add(serviceNode.getId());
			return true;
		}
	}
	
	
	
	

	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#removeDependency(com.feedzai.service.data.ServiceNode)
	 */
	@Override
	public boolean removeIsChildFromDependency(ServiceNode serviceNode) {
		
		// The ID has to be a natural number and node cannot be null
		if(serviceNode == null || serviceNode.getId() == null || serviceNode.getId().longValue() < ZERO)
		{
			throw new IllegalArgumentException("The node is null or de ID is not valid");
		}
		
		else
		{
			//
			// We should check if the dependencies exist or not
			//
			if(serviceNode.getId().equals(getId()) || !(isChildFromLinkedList.contains(serviceNode.getId())))
				return false;
			
			else
			{
				// We updated the dependencies successfully 
				isChildFromLinkedList.remove(serviceNode.getId());
				return true;
			}
		}
	}
	
	
	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#addParentDependency(com.feedzai.service.data.ServiceNode)
	 */
	@Override
	public boolean addIsParentFromDependency(ServiceNode serviceNode) 
	{
		// The ID has to be a natural number and node cannot be null
		if(serviceNode == null || serviceNode.getId() == null || serviceNode.getId().longValue() < ZERO)
		{
			throw new IllegalArgumentException("The node is null or de ID is not valid");
		}
		else
		{
			//
			// We should not consider dependencies which have the same ID as the current service
			// Or dependencies that are already created. Thus, avoid duplicates
			//
			if(serviceNode.getId().equals(this.getId()) || isParentFromLinkedList.contains(serviceNode.getId()))
				return false;
			
			// We include a new dependency with no problems
			isParentFromLinkedList.add(serviceNode.getId());
			return true;
		}
	}


	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#removeParentDependency(com.feedzai.service.data.ServiceNode)
	 */
	@Override
	public boolean removeIsParentFromDependency(ServiceNode serviceNode) 
	{
		// The ID has to be a natural number and node cannot be null
		if(serviceNode == null || serviceNode.getId() == null || serviceNode.getId().longValue() < ZERO)
		{
			throw new IllegalArgumentException("The node is null or de ID is not valid");
		}
		
		else
		{
			//
			// We should check if the dependencies exist or not
			//
			if(serviceNode.getId().equals(getId()) || !(isParentFromLinkedList.contains(serviceNode.getId())))
				return false;
			
			else
			{
				// We updated the dependencies successfully 
				isParentFromLinkedList.remove(serviceNode.getId());
				return true;
			}
		}
	}

	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#getDependencies()
	 */
	@Override
	public LinkedList<Long> getIsChildFromDependencies() {
		
		return isChildFromLinkedList;
	}


	/* (non-Javadoc)
	 * @see com.feedzai.service.ServiceInterface#getParentDependencies()
	 */
	@Override
	public LinkedList<Long> getIsParentFromDependencies() {
		
		return isParentFromLinkedList;
	}
}
